use crate::gen_title;

pub fn ch2_21_1() {
    gen_title("ch2_21_1", 18);

    let v = vec![1, 2, 3, 4, 5];

    let third: &i32 = &v[2];
    println!("第三个元素是: {}", third);

    match v.get(2) {
        Some(third) => println!("第三个元素是: {}", third),
        None => println!("没有第三个元素"),
    }
}

pub fn ch2_21_2() {
    gen_title("ch2_21_2", 18);

    let mut v = vec![1, 2, 3, 4, 5];
    let first = &v[0];

    println!("第一个元素是: {}", first);

    v.push(6);
    println!("{:?}", v);
}

pub fn ch2_21_3() {
    gen_title("ch2_21_3", 18);

    let v = vec![1, 2, 3];
    for i in &v {
        println!("{i}");
    }

    let mut v = vec![1, 2, 3];
    for i in &mut v {
        *i += 10;
    }
    println!("{:?}", v);
}

pub fn ch2_21_4() {
    gen_title("ch2_21_4", 18);

    #[derive(Debug)]
    enum IpAddr {
        V4(String),
        V6(String),
    }

    let v = vec![
        IpAddr::V4("127.0.0.1".to_string()),
        IpAddr::V6("::1".to_string()),
    ];

    for ip in v {
        show_addr(ip)
    }

    fn show_addr(ip: IpAddr) {
        println!("{:?}", ip);
    }
}

pub fn ch2_21_5() {
    gen_title("ch2_21_5", 18);

    trait IpAddr {
        fn display(&self);
    }

    struct V4(String);

    impl IpAddr for V4 {
        fn display(&self) {
            println!("V4: {}", self.0);
        }
    }

    struct V6(String);
    impl IpAddr for V6 {
        fn display(&self) {
            println!("V6: {}", self.0);
        }
    }

    let v: Vec<Box<dyn IpAddr>> = vec![
        Box::new(V4("127.0.0.1".to_string())),
        Box::new(V6("::1".to_string())),
    ];

    for ip in v {
        ip.display();
    }
}

pub fn ch2_21_6() {
    gen_title("ch2_21_6", 18);

    let v = vec![0; 3];
    let v_from = Vec::from([0, 0, 0]);
    assert_eq!(v, v_from);

    let mut v = Vec::with_capacity(10);
    v.extend([1, 2, 3]);
    println!("Vector 长度是: {}, 容量是: {}", v.len(), v.capacity());

    v.reserve(100);
    println!("Vector 长度是: {}, 容量是: {}", v.len(), v.capacity());

    v.shrink_to_fit();
    println!("Vector 长度是: {}, 容量是: {}", v.len(), v.capacity());
}

pub fn ch2_21_7() {
    gen_title("ch2_21_7", 18);

    let mut v = vec![1, 2];
    assert!(!v.is_empty());

    v.insert(2, 3);
    println!("{:?}", v);
    assert_eq!(v.remove(1), 2);
    println!("{:?}", v);
    assert_eq!(v.pop(), Some(3));
    println!("{:?}", v);
    assert_eq!(v.pop(), Some(1));
    println!("{:?}", v);
    assert_eq!(v.pop(), None);
    println!("{:?}", v);
    v.clear();

    let mut v1 = [11, 22].to_vec();
    v.append(&mut v1);
    println!("{:?}", v);
    v.truncate(1);
    println!("{:?}", v);
    v.retain(|x| *x > 10);
    println!("{:?}", v);

    let mut v = vec![11, 22, 33, 44, 55];
    let mut m: Vec<_> = v.drain(1..=3).collect();
    println!("{:?}", m);
    println!("{:?}", v);

    let v2 = m.split_off(1);
    println!("{:?}", v2);
    println!("{:?}", m);

    let v = vec![11, 22, 33, 44, 55];
    let slice = &v[1..=3];
    assert_eq!(slice, &[22, 33, 44]);
    println!("{:?}", slice);
    println!("{:?}", v);
}

pub fn ch2_21_8() {
    gen_title("ch2_21_8", 18);

    let mut vec = vec![1, 5, 10, 2, 15];
    vec.sort_unstable();
    assert_eq!(vec, vec![1, 2, 5, 10, 15]);
    println!("{:?}", vec);

    let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];
    vec.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
    println!("{:?}", vec);
}

pub fn ch2_21_9() {
    gen_title("ch2_21_9", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u32,
    }

    impl Person {
        fn new(name: String, age: u32) -> Person {
            Person { name, age }
        }
    }

    let mut people = vec![
        Person::new("Zoe".to_string(), 25),
        Person::new("Al".to_string(), 60),
        Person::new("John".to_string(), 1),
    ];

    people.sort_unstable_by(|a, b| b.age.cmp(&a.age));

    println!("{:?}", people);
}

pub fn ch2_21_10() {
    gen_title("ch2_21_10", 18);

    #[derive(Debug, Ord, Eq, PartialEq, PartialOrd)]
    struct Person {
        name: String,
        age: u32,
    }

    impl Person {
        fn new(name: String, age: u32) -> Person {
            Person { name, age }
        }
    }

    let mut people = vec![
        Person::new("Zoe".to_string(), 25),
        Person::new("Al".to_string(), 60),
        Person::new("Al".to_string(), 30),
        Person::new("John".to_string(), 1),
        Person::new("John".to_string(), 25),
    ];

    people.sort_unstable();

    println!("{:?}", people);
}

pub fn ch2_21_pra_1() {
    gen_title("ch2_21_pra_1", 18);

    let arr: [u8; 3] = [1, 2, 3];

    let v = Vec::from(arr);
    is_vec(v);

    let v = vec![1, 2, 3];
    is_vec(v);

    let mut v = vec![1, 3, 3];
    is_vec(v);

    let mut v1 = vec![];
    v1.append(&mut arr.to_vec());
    println!("{:?}", v1);

    fn is_vec(v: Vec<u8>) {
        println!("{:?}", v);
    }
}

pub fn ch2_21_pra_2() {
    gen_title("ch2_21_pra_2", 18);

    let mut v1 = Vec::from([1, 2, 4]);

    v1.pop();
    v1.push(3);

    let mut v2 = Vec::new();
    v2.extend([1, 2, 3]);

    assert_eq!(v1, v2);

    println!("{:?}", v1);
    println!("{:?}", v2);
}

pub fn ch2_21_pra_3() {
    gen_title("ch2_21_pra_3", 18);

    let arr = [1, 2, 3];
    let v1 = Vec::from(arr);
    let v2: Vec<i32> = arr.to_vec();

    assert_eq!(v1, v2);

    let s = "hello".to_string();
    let v1: Vec<u8> = s.into();

    let s = "hello".to_string();
    let v2 = s.into_bytes();
    assert_eq!(v1, v2);

    let s = "hello";
    let v3 = Vec::from(s);
    assert_eq!(v2, v3);

    let v4: Vec<i32> = [0; 10].into_iter().collect();
    assert_eq!(v4, vec![0; 10]);

    println!("{:?}", v4)
}

pub fn ch2_21_pra_4() {
    gen_title("ch2_21_pra_4", 18);

    let mut v = Vec::from([1, 2, 3]);

    for i in 0..5 {
        println!("{:?}", v.get(i));
    }

    for i in 0..5 {
        if let Some(x) = v.get(i) {
            v[i] = i + 2;
        } else {
            v.push(i + 2);
        }
    }

    assert_eq!(v, vec![2, 3, 4, 5, 6]);

    println!("{:?}", v);
}

pub fn ch2_21_pra_5() {
    gen_title("ch2_21_pra_5", 18);

    let mut v = vec![1, 2, 3];

    let slice1 = &v[..];
    let slice2 = &v[0..v.len()];

    assert_eq!(slice1, slice2);

    let vec_ref: &mut Vec<i32> = &mut v;
    vec_ref.push(4);
    let slice3 = &mut v[0..];

    assert_eq!(slice3, &[1, 2, 3, 4]);

    println!("Success");
}

pub fn ch2_21_pra_6() {
    gen_title("ch2_21_pra_6", 18);

    let mut vec = Vec::with_capacity(10);

    assert_eq!(vec.len(), 0);
    assert_eq!(vec.capacity(), 10);
    println!("len: {}, capacity: {}", vec.len(), vec.capacity());

    for i in 0..10 {
        vec.push(i);
    }

    assert_eq!(vec.len(), 10);
    assert_eq!(vec.capacity(), 10);
    println!("len: {}, capacity: {}", vec.len(), vec.capacity());

    vec.push(11);
    assert_eq!(vec.len(), 11);
    assert_eq!(vec.capacity(), 20);
    println!("len: {}, capacity: {}", vec.len(), vec.capacity());

    let mut vec = Vec::with_capacity(100);
    for i in 0..100 {
        vec.push(i);
    }

    assert_eq!(vec.len(), 100);
    assert_eq!(vec.capacity(), 100);
    println!("len: {}, capacity: {}", vec.len(), vec.capacity());

    println!("Success");
}

pub fn ch2_21_pra_7() {
    gen_title("ch2_21_pra_7", 18);

    #[derive(Debug, PartialEq)]
    enum IpAddr {
        V4(String),
        V6(String),
    }

    let v: Vec<IpAddr> = vec![
        IpAddr::V4("127.0.0.1".to_string()),
        IpAddr::V6("::1".to_string()),
    ];

    assert_eq!(v[0], IpAddr::V4("127.0.0.1".to_string()));
    assert_eq!(v[1], IpAddr::V6("::1".to_string()));

    println!("{:?}", v);
}

pub fn ch2_21_pra_8() {
    gen_title("ch2_21_pra_8", 18);

    trait IpAddr {
        fn display(&self);
    }

    struct V4(String);

    impl IpAddr for V4 {
        fn display(&self) {
            println!("V4: {}", self.0);
        }
    }

    struct V6(String);

    impl IpAddr for V6 {
        fn display(&self) {
            println!("V6: {}", self.0);
        }
    }

    let v: Vec<Box<dyn IpAddr>> = vec![
        Box::new(V4("127.0.0.1".to_string())),
        Box::new(V6("::1".to_string())),
    ];

    for ip in v {
        ip.display();
    }
}
